package com.heima.article.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.FreemarkerService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.model.common.dtos.ArticleDto;
import com.heima.model.common.dtos.ArticleHomeDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.pojos.article.ApArticle;
import com.heima.model.common.pojos.article.ApArticleConfig;
import com.heima.model.common.pojos.article.ApArticleContent;
import com.heima.model.common.vo.ApArticleVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 陈辉
 * @data 2024 9:50
 */
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;
    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;
    @Autowired
    private ApArticleContentMapper apArticleContentMapper;
    @Autowired
    private FreemarkerService freemarkerService;
    @Autowired
    private CacheService cacheService;

    /**
     * 加载文章信息
     *
     * @param homeDto 查询条件
     * @param type    1：加载更多 2：加载更新
     * @return
     */
    @Override
    public ResponseResult load(ArticleHomeDto homeDto, int type) {
        //1. 参数校验
        if (homeDto == null || (type != 1 && type != 2)) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2. 数据处理
        if (homeDto.getMaxBehotTime() == null) homeDto.setMaxBehotTime(new Date());
        if (homeDto.getMinBehotTime() == null) homeDto.setMinBehotTime(new Date());
        if (homeDto.getSize() < 1 || homeDto.getSize() > 50) homeDto.setSize(10);

        //3. 调用mapper查询对应数据
        List<ApArticle> res = apArticleMapper.load(homeDto, type);

        //4. 封装结果返回
        return ResponseResult.okResult(res);
    }

    /**
     * 保存或修改文章信息
     *
     * @param articleDto
     * @return
     */
    @Override
    public ResponseResult saveOrUpdateArticle(ArticleDto articleDto) {
        //1. 同步自媒体文章信息
        if (articleDto.getId() == null) {
            //保存
            //1. 保存文章基本信息：ap_article
            ApArticle apArticle = new ApArticle();
            BeanUtils.copyProperties(articleDto, apArticle);
            apArticleMapper.insert(apArticle);
            articleDto.setId(apArticle.getId());

            //2. 创建文章默认配置：ap_article_config
            ApArticleConfig config = new ApArticleConfig(apArticle.getId());
            apArticleConfigMapper.insert(config);

            //3. 保存文章内容信息：ap_article_content
            ApArticleContent content = new ApArticleContent();
            content.setArticleId(apArticle.getId());
            content.setContent(articleDto.getContent());
            apArticleContentMapper.insert(content);
        } else {
            //修改
            //1. 修改文章基本信息：ap_article
            ApArticle apArticle = new ApArticle();
            BeanUtils.copyProperties(articleDto, apArticle);
            apArticleMapper.updateById(apArticle);

            //2. 修改文章内容信息：ap_article_content
            ApArticleContent content = new ApArticleContent();
            content.setArticleId(apArticle.getId());
            content.setContent(articleDto.getContent());
            //update ap_article_content set ? ,? where article_id = ?
            apArticleContentMapper.update(content,
                    Wrappers.<ApArticleContent>lambdaUpdate().eq(ApArticleContent::getArticleId, content.getArticleId()));
        }

        //2. 采用异步调用，提升当前接口的性能，生成文章详情页： freemarker + minio
        freemarkerService.generateDetailHtml(articleDto);


        //将文章id返回
        return ResponseResult.okResult(String.valueOf(articleDto.getId()));
    }


    /**
     * 文章上下架
     * <p>
     * is_down: 0: 上架， 1：下架
     *
     * @param map enable 0：下架， 1：上架
     */
    @Override
    public void downOrUp(Map map) {
        boolean isDown = true;            // 假设要下架

        if ((int) map.get("enable") == 1) {
            isDown = false;
        }
        ApArticleConfig config = new ApArticleConfig();
        //config.setArticleId((long) map.get("article_id"));
        //update ap_article_config set is_down = ? where article_id = ?
        apArticleConfigMapper.update(config, Wrappers.<ApArticleConfig>lambdaUpdate()
                .set(ApArticleConfig::getIsDown, isDown)
                .eq(ApArticleConfig::getArticleId, config.getArticleId()));

    }

    /**
     * 自媒体-评论管理的打开或关闭
     *
     * @param articleId
     * @param isComment
     */
    @Override
    public void updateIsCommentStatus(Long articleId, Integer isComment) {
        //修改ap_article_config表中的is_comment
        //1.1查询出对应的文章
        ApArticleConfig apArticleConfig = apArticleConfigMapper.selectOne(Wrappers.<ApArticleConfig>lambdaQuery().eq(ApArticleConfig::getArticleId, articleId));
        if (Objects.isNull(apArticleConfig)) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        if (isComment == 0) {
            apArticleConfig.setIsComment(false);
        } else {
            apArticleConfig.setIsComment(true);
        }

        apArticleConfigMapper.updateById(apArticleConfig);
    }


    /**
     * 自媒体端-评论管理的清空评论数量
     *
     * @param articleId
     */
    @Override
    public void deleteAllComment(Long articleId) {
        //todo::这里的清空不是删除是修改ap_article表中的comment字段
        //根据文章ID查询对应的文章
        ApArticle apArticle = apArticleMapper.selectOne(Wrappers.<ApArticle>lambdaQuery().eq(ApArticle::getId, articleId));
        if (apArticle == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        //修改comment字段
        apArticle.setComment(0);
        apArticleMapper.updateById(apArticle);
    }

    /**
     * 查找作者信息
     *
     * @param articleId
     * @return
     */
    @Override
    public ResponseResult queryArticle(Long articleId) {
        ApArticle article = getById(articleId);
        return ResponseResult.okResult(article);
    }

    @Override
    public ResponseResult updateArticle(ArticleDto articleDto) {
        ApArticle article = getById(articleDto.getId());
        if (articleDto.getComment()!=null&&article.getComment()>0)
            article.setComment(article.getComment()+articleDto.getComment());
        updateById(article);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 存入文章的用户行为信息
     *
     * @param articleDto
     * @return
     */
    @Override
    public ResponseResult behaviorArticle(ArticleDto articleDto) {


        if (articleDto == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);

        ApArticle article = getById(articleDto.getAuthorId());
        //修改点赞量
        if (article.getLikes() != null && article.getLikes() >= 1 && articleDto.getLikes() != null){
            article.setLikes(article.getLikes()+articleDto.getLikes());
        }else if (articleDto.getLikes() != null){
            article.setLikes(articleDto.getLikes());
        }
        //修改关注量
        if (article.getCollection() != null && article.getCollection() >= 1 && articleDto.getCollection() != null){

            article.setCollection(article.getCollection()+articleDto.getCollection());
        }else if (articleDto.getCollection() != null){
            article.setCollection(articleDto.getCollection());
        }
        //修改阅读量
        if (article.getViews() != null && articleDto.getViews() != null){
            article.setViews(article.getViews()+articleDto.getViews());
        }else if (articleDto.getViews() != null){
            article.setViews(articleDto.getViews());
        }

        updateById(article);


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 查询文章是否可以评论
     *
     * @param articleId
     * @return
     */
    @Override
    public ResponseResult isComment(String articleId) {
        Integer number = apArticleConfigMapper.selectByArticleId(Long.valueOf(articleId),1);
        return ResponseResult.okResult(number);
    }

    @Override
    public void computeHotArticleJob() {
        //1.查询近5天的文章数据
        Date now = new Date();
        Date fiveDaysAgo = new Date(System.currentTimeMillis() - (1000L*60*60*20*5));
        List<ApArticle> apArticleList = apArticleMapper.loadFiveDaysDate(fiveDaysAgo);
        //2.给文章算分
        List<ApArticleVo> apArticleVos = computeScore(apArticleList);
        //3.计算每个频道的热点文章，存入redis
        //3.1提取出当前这些文章对应的频道id
        List<Integer> channelIds = apArticleVos.stream().map(ApArticleVo::getChannelId).distinct().collect(Collectors.toList());
        //3.2遍历频道，收集每个频道的文章
        channelIds.forEach(
                channelId->{
                    List<ApArticleVo> hotArticleInSameChannel = apArticleVos.stream().filter(apArticleVo -> apArticleVo.getChannelId() == channelId)
                            .sorted(((o1, o2) -> o2.getScore() - o1.getScore()))
                            .limit(30)
                            .collect(Collectors.toList());
                    cacheService.set("hot_article"+channelId, JSONArray.toJSONString(hotArticleInSameChannel));
                });
        //4.计算推荐频道的热点文章，存入redis
        List<ApArticleVo> hotArticleInWithAllChannel = apArticleVos.stream().sorted(((o1, o2) -> o2.getScore() - o1.getScore()))
                .limit(30)
                .collect(Collectors.toList());
        cacheService.set("hot_article_all_",JSONArray.toJSONString(hotArticleInWithAllChannel));
    }

    @Override
    public ResponseResult loadHotArticle(ArticleHomeDto homeDto, int type) {
        String hotArticleJSON = cacheService.get("hot_article_" + homeDto.getTag());
        if(StringUtils.isNotBlank(hotArticleJSON)){
            return ResponseResult.okResult(JSONArray.parseArray(hotArticleJSON));
        }
        return load(homeDto,type);
    }


    private List<ApArticleVo> computeScore(List<ApArticle> apArticleList) {
        List<ApArticleVo> ApArticleVos = new ArrayList<>();
        apArticleList.forEach(
                apArticle -> {
                    ApArticleVo apArticleVo = new ApArticleVo();
                    Integer score = 0;
                    if(apArticle.getLikes() != null){
                        score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
                    }
                    if(apArticle.getViews() != null){
                        score += apArticle.getViews();
                    }
                    if(apArticle.getComment() != null){
                        score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
                    }
                    if(apArticle.getCollection() != null){
                        score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
                    }
                    apArticleVo.setScore(score);
                    ApArticleVos.add(apArticleVo);
                }
        );
        return ApArticleVos;
    }
}
